﻿using lctdevice;
using Microsoft.Extensions.Logging;
using RotovapPlatform.Domain.Equipment.Interfaces.Base;
using RotovapPlatform.Domain.Equipment.Interfaces.Communication;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RotovapPlatform.Infrastructure.Equipment.Communication.Ethercat
{
	public class EtherCATManager : IEtherCATManager
	{
		// 日志记录器
		private readonly ILogger<EtherCATManager> _logger;
		// 轴卡ID 初始化为0
		public short CardId { get; set; } = 0;
		public bool IsConnected => throw new NotImplementedException();
		//从站数量
		public short SlaveNum { get; set; }
		//轴数量
		public short AxisNum { get; set; }
		//IO从站数量
		public short IoSlaveNum { get; set; }
		//DI数量
		public short DiNum { get; set; }
		//DO数量
		public short DoNum { get; set; }
		//AI数量
		public short AiNum { get; set; }
		//AO数量
		public short AoNum { get; set; }

		//所有轴的状态，int数组
		public int[] AllAxisStatus { get; set; }

		//所有轴的位置，int数组
		public int[] AllAxisPosition { get; set; }

		//所有轴的速度，double数组
		public double[] AllAxisVelocity { get; set; }

		//所有轴的扭矩，int数组
		public short[] AllAxisTorque { get; set; }

		//所有轴的规划位置，double数组
		public double[] AllAxisPlanPosition { get; set; }

		//所有轴的规划速度，double数组
		public double[] AllAxisPlanVelocity { get; set; }

		private readonly object _statusLock = new();


		bool IConnectable.IsConnected { get => IsConnected; set => throw new NotImplementedException(); }

		public EtherCATManager(ILogger<EtherCATManager> logger)
		{
			_logger = logger;
		}

		public Task<bool> CheckConnectionAsync()
		{
			throw new NotImplementedException();
		}

		public Task<bool> ConnectAsync()
		{
			try
			{
				short ret = ecat_motion.M_Open(CardId, 0);
				_logger.LogInformation("打开轴卡{CardId}", CardId);

				if (ret != 0)
				{
					_logger.LogError("轴卡打开失败，错误码：{ErrorCode}", ret);
					return Task.FromResult(false);
				}

				_logger.LogInformation("轴卡{CardId}打开成功", CardId);

				// 配置急停参数
				ConfigureEmergencyStop(CardId);

				// FPGA重置
				if (!ResetFpga(CardId))
					return Task.FromResult(false);

				// 连接EtherCAT总线
				return ConnectEtherCAT(CardId);

			}
			catch (Exception ex)
			{
				_logger.LogCritical(ex, "轴卡初始化过程中发生异常");
				return Task.FromResult(false);
			}
		}

		public void DisconnectAsync()
		{
			try//尝试使所有的轴去使能
			{
				for (short i = 1; i < AxisNum + 1; i++)
					ecat_motion.M_Servo_Off(i, 0);
				Thread.Sleep(100);
			}
			catch { }

			try//尝试断开EtherCAT总线
			{
				short ret1 = ecat_motion.M_DisconnectECAT(CardId);//断开总线段
			}
			catch { }

			short ret2 = ecat_motion.M_Close(CardId);
			_logger.LogInformation("关闭轴卡{CardId}", CardId);
		}

		public Task<int> GetAxisErrorCodeAsync(int axisId)
		{
			throw new NotImplementedException();
		}

		public Task<bool> GetAllAxisStatusAsync()
		{
			try
			{
				//获取状态
				short ret = ecat_motion.M_GetSts(1, out AllAxisStatus[0], AxisNum, CardId);
				//获取位置
				short ret2 = ecat_motion.M_ReadActualPosition(1, out AllAxisPosition[0], AxisNum, CardId);
				//获取速度
				short ret3 = ecat_motion.M_GetEncVel(1, out AllAxisVelocity[0], AxisNum, CardId);
				//获取扭矩
				short ret4 = ecat_motion.M_ReadActualTorque(1, ref AllAxisTorque[0], AxisNum, CardId);
				//获取规划位置
				short ret5 = ecat_motion.M_GetCmd(1, out AllAxisPlanPosition[0], AxisNum, CardId);
				//获取规划速度
				short ret6 = ecat_motion.M_GetCmdVel(1, out AllAxisPlanVelocity[0], AxisNum, CardId);

				return Task.FromResult(ret == 0 && ret2 == 0 && ret3 == 0 && ret4 == 0 && ret5 == 0 && ret6 == 0);
			}
			catch (Exception ex)
			{
				_logger.LogError(ex, "获取轴状态失败");
				return Task.FromResult(false);
			}
		}

		public int GetAxisStatus(int axisId)
		{
			if (axisId < 1 || axisId > AxisNum)
			{
				_logger.LogWarning("轴ID {AxisId} 超出范围", axisId);
				return -1;
			}

			lock (_statusLock)
			{
				return AllAxisStatus[axisId - 1];
			}
		}

		//获取某个电机的位置
		public int GetAxisPosition(int axisId)
		{
			if (axisId < 1 || axisId > AxisNum)
			{
				_logger.LogWarning("轴ID {AxisId} 超出范围", axisId);
				return -1;
			}
			return AllAxisPosition[axisId - 1];
		}

		//获取某个电机的速度
		public double GetAxisVelocity(int axisId)
		{
			if (axisId < 1 || axisId > AxisNum)
			{
				_logger.LogWarning("轴ID {AxisId} 超出范围", axisId);
				return -1;
			}
			return AllAxisVelocity[axisId - 1];
		}

		//获取某个电机的扭矩
		public int GetAxisTorque(int axisId)
		{
			if (axisId < 1 || axisId > AxisNum)
			{
				_logger.LogWarning("轴ID {AxisId} 超出范围", axisId);
				return -1;
			}
			return AllAxisTorque[axisId - 1];
		}

		//获取某个电机的规划位置
		public double GetAxisPlanPosition(int axisId)
		{
			if (axisId < 1 || axisId > AxisNum)
			{
				_logger.LogWarning("轴ID {AxisId} 超出范围", axisId);
				return -1;
			}
			return AllAxisPlanPosition[axisId - 1];
		}

		//获取某个电机的规划速度	
		public double GetAxisPlanVelocity(int axisId)
		{
			if (axisId < 1 || axisId > AxisNum)
			{
				_logger.LogWarning("轴ID {AxisId} 超出范围", axisId);
				return -1;
			}
			return AllAxisPlanVelocity[axisId - 1];
		}

		private void ConfigureEmergencyStop(short card)
		{
			ecat_motion.M_SetEmgAction(0x00, card);
			ecat_motion.M_SetEmgInv(0, card);
			ecat_motion.M_ClrEmg(card);
		}

		private bool ResetFpga(short card)
		{
			short ret = ecat_motion.M_ResetFpga(card);
			if (ret != 0)
			{
				_logger.LogError("FPGA重置失败，错误码：{ErrorCode}", ret);
				return false;
			}
			Thread.Sleep(500);
			return true;
		}

		private Task<bool> ConnectEtherCAT(short card)
		{
			short ret = ecat_motion.M_LoadEni("C:\\Program Files (x86)\\LCT\\PCIe-M60\\Eni\\eni.xml", card);
			if (ret != 0)
			{
				HandleEniLoadError(ret);
				return Task.FromResult(false);
			}

			ret = ecat_motion.M_LoadEcatConfigDefault(card);
			if (ret != 0)
			{
				_logger.LogError("加载Ecat配置失败，错误码：{ErrorCode}", ret);
				return Task.FromResult(false);
			}

			short option = 0;
			ret = ecat_motion.M_ConnectECAT(option, card);
			if (ret != 0)
			{
				_logger.LogError("总线连接失败，错误码：{ErrorCode}", ret);
				return Task.FromResult(false);
			}

			Thread.Sleep(500);
			return LoadParametersAndVerify(card);


		}

		private Task<bool> LoadParametersAndVerify(short card)
		{
			short ret = ecat_motion.M_LoadParamFromFile("C:\\Program Files (x86)\\LCT\\PCIe-M60\\Motion_Assistant\\AxisParam\\ParamCard0.ini", card);
			if (ret != 0)
			{
				_logger.LogError("参数加载失败，错误码：{ErrorCode}", ret);
				return Task.FromResult(false);
			}

			ecat_motion.SL_RES Sl_res = new ecat_motion.SL_RES();
			ret = ecat_motion.M_GetSlaveResource(out Sl_res, card);
			if (ret == 0)
			{
				//从站数量
				SlaveNum = (short)Sl_res.SlaveNum;
				//轴数量
				AxisNum = (short)Sl_res.AxisNum;
				//IO从站数量
				IoSlaveNum = (short)Sl_res.IoSlaveNum;
				//DI数量
				DiNum = (short)Sl_res.DiNum;
				//DO数量
				DoNum = (short)Sl_res.DoNum;
				//AI数量
				AiNum = (short)Sl_res.AiNum;
				//AO数量
				AoNum = (short)Sl_res.AoNum;

				AllAxisStatus = new int[AxisNum];
				AllAxisPosition = new int[AxisNum];
				AllAxisVelocity = new double[AxisNum];
				AllAxisTorque = new short[AxisNum];
				AllAxisPlanPosition = new double[AxisNum];
				AllAxisPlanVelocity = new double[AxisNum];

				_logger.LogInformation("轴卡初始化成功！从站数量：{SlaveCount}", Sl_res.SlaveNum);

				////CloseCard();
				//ClearAxisError();
				//ClearAxisEmergencyStop();
				//GetAllAxisStatusAsync();
				//GetAllAxisStatusAsync();
				ClearAxisError();

				return Task.FromResult(true);
			}

			_logger.LogError("从站资源验证失败，错误码：{ErrorCode}", ret);
			return Task.FromResult(false);
		}

		private void HandleEniLoadError(short errorCode)
		{
			switch (errorCode)
			{
				case 10:
					_logger.LogError("ENI文件加载失败：文件路径错误或权限不足");
					break;
				case 20:
					_logger.LogError("ENI文件格式错误");
					break;
				default:
					_logger.LogError("未知的ENI加载错误，错误码：{ErrorCode}", errorCode);
					break;
			}
		}

		public Task<bool> ClearAxisError()
		{
			short ret = ecat_motion.M_ClrSts(1, AxisNum, CardId);//第2个参数为将要执行的轴的数量
			_logger.LogError("清除当前轴的错误轴状态和驱动器报警", ret);
			return Task.FromResult(ret == 0);
		}

		public Task<bool> ClearAxisEmergencyStop()
		{
			short ret = ecat_motion.M_ClrEmg(CardId);
			_logger.LogError("清除当前轴的急停信号", ret);
			return Task.FromResult(ret == 0);
		}

		Task<int> IEtherCATManager.GetAxisErrorCodeAsync()
		{
			throw new NotImplementedException();
		}
	}
}

